home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 22
/
AACD 22.iso
/
AACD
/
Resources
/
Sound
/
AHI
/
Developer
/
examples
/
Device
/
AHI-Handler
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-04-08
|
31KB
|
1,143 lines
/* $Id: main.c,v 4.2 1997/04/09 01:55:32 lcs Exp $
* $Log: main.c,v $
* Revision 4.2 1997/04/09 01:55:32 lcs
* Much improved error handling.
*
* Revision 4.1 1997/04/02 22:46:37 lcs
* Bumped to version 4
*
* Revision 1.8 1997/03/27 12:11:25 lcs
* Never mind! Bah.
*
* Revision 1.7 1997/03/26 13:32:43 lcs
* Added UNIT to the template, and set taskpri to 5.
*
* Revision 1.6 1997/02/01 14:10:08 lcs
* A couple of bugs fixed.
*
* Revision 1.5 1997/01/29 15:44:49 lcs
* It's "finished"!
*
* Revision 1.4 1997/01/24 23:20:47 lcs
* Writing seem to work too...
*
* Revision 1.3 1997/01/23 19:55:50 lcs
* Added AIFF and AIFC saving.
*
* Revision 1.2 1997/01/21 23:56:21 lcs
* Reading seem to work okay now.
*
* Revision 1.1 1997/01/17 23:34:28 lcs
* Initial revision
*
*/
/*
* This code is written using DICE, and is based on the DosHan example
* source code that came with the compiler. Not all comments are mine,
* by the way...
*
* Done by Martin Blom 1997. Public Domain.
*
*/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <dos/rdargs.h>
#include <devices/ahi.h>
#include <proto/ahi.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
/*
* Prototypes
*/
LONG PlayAndSwap(struct HandlerData *, LONG);
long extended2long(extended *);
void ulong2extended (ULONG, extended *);
void FillAIFFheader(struct HandlerData *);
void FillAIFCheader(struct HandlerData *);
LONG ReadCOMMchunk(struct HandlerData *, UBYTE *, LONG);
long AllocAudio(int);
void FreeAudio(void);
long ParseArgs(struct HandlerData *, char *);
long InitHData(struct HandlerData *);
void FreeHData(struct HandlerData *);
void returnpacket (struct DosPacket *);
void Initialize (void);
void UnInitialize (void);
/*
* Some macros
*/
#define min(a,b) ((a)<=(b)?(a):(b))
#define DOS_TRUE -1
#define DOS_FALSE 0
#define BTOC(bptr) ((void *)((long)(bptr) << 2))
#define CTOB(cptr) ((BPTR)(((long)cptr) >> 2))
/*
* My debug stuff....
*/
#define HIT(x) {char *a=NULL; *a=x;}
void kprintf(char *, ...);
/*
* Global variables
*/
const static char ID[] = "$VER: AHI-Handler 4.2 (9.4.97)\r\n";
struct List HanList;
struct DeviceNode *DevNode;
struct MsgPort *PktPort;
int AllocCnt;
BOOL Running;
struct MsgPort *AHImp = NULL;
struct AHIRequest *AHIio = NULL;
BYTE AHIDevice = -1;
struct Library *AHIBase;
struct AIFCHeader AIFCHeader = {
ID_FORM, NULL, ID_AIFC,
ID_FVER, sizeof(FormatVersionHeader), {
AIFCVersion1
},
ID_COMM, sizeof(ExtCommonChunk), {
0,
0,
0,
{0},
NO_COMPRESSION,
sizeof("not compressed")-1,
'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'
},
ID_SSND, NULL, {0,0}
};
struct AIFFHeader AIFFHeader = {
ID_FORM, NULL, ID_AIFF,
ID_COMM, sizeof(CommonChunk),{
0,
0,
0,
{0}
},
ID_SSND, NULL, {0,0}
};
/******************************************************************************
**** Entry ********************************************************************
******************************************************************************/
/*
* Note that we use the _main entry point. Also notice that we do not
* need to open any libraries.. they are openned for us via DICE's
* unique auto-library-open ability.
*/
void _main ()
{
struct DosPacket *packet;
struct Process *proc = (struct Process *) FindTask (NULL);
PktPort = &proc->pr_MsgPort;
NewList (&HanList);
Initialize ();
Running = TRUE;
AllocCnt = 0;
#ifdef DEBUG
kprintf("Init\n");
#endif
/*
* Main Loop
*/
while(Running) {
struct Message *msg;
while ((msg = GetMsg (PktPort)) == NULL)
Wait (1 << PktPort->mp_SigBit);
packet = (struct DosPacket *) msg->mn_Node.ln_Name;
/*
* default return value
*/
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
/*
* switch on packet
*/
switch (packet->dp_Type) {
case ACTION_DIE: /* ??? */
{
break;
}
/***********************************************************************/
case ACTION_FINDUPDATE: /* FileHandle,Lock,Name Bool */
case ACTION_FINDINPUT: /* FileHandle,Lock,Name Bool */
case ACTION_FINDOUTPUT: /* FileHandle,Lock,Name Bool */
{
struct FileHandle *fh = BTOC (packet->dp_Arg1);
unsigned char *base = BTOC (packet->dp_Arg3);
int len = *base;
char buf[128];
struct HandlerData *data;
int unit = AHI_DEFAULT_UNIT;
// Skip volume name and ':'
while(*++base != ':')
--len;
++base;
{
// Convert /'s to blanks
char *p = base;
while(*++p)
if(*p == '/')
*p = ' ';
}
if (len >= sizeof (buf))
len = sizeof (buf) - 1;
strncpy (buf, base, len - 1);
buf[len - 1] = '\n';
buf[len] = 0;
#ifdef DEBUG
kprintf("ACTION_FIND#?: %s\n", (char *) buf);
#endif
data = AllocVec(sizeof(struct HandlerData), MEMF_PUBLIC | MEMF_CLEAR);
if(! data) {
packet->dp_Res1 = DOS_FALSE;
packet->dp_Res2 = ERROR_NO_FREE_STORE;
break;
}
if(packet->dp_Res2 = ParseArgs(data, (char *) buf)) {
FreeHData(data);
packet->dp_Res1 = DOS_FALSE;
break;
}
if(data->args.unit) {
unit = *data->args.unit;
}
if(packet->dp_Res2 = AllocAudio(unit)) {
FreeAudio();
FreeHData(data);
packet->dp_Res1 = DOS_FALSE;
break;
}
fh->fh_Arg1 = (ULONG) data;
fh->fh_Port = (struct MsgPort *) DOS_TRUE;
break;
}
/***********************************************************************/
case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
{
/*
* Reading is straightforward except for handling EOF... We
* must guarentee a return value of 0 (no bytes left) before
* beginning to return EOFs (-1's). If we return a negative
* number right off programs like COPY will assume a failure
* (if AUDIO: is the source) and delete the destination file.
*
* The basic idea is to feed the packets from one buffer while
* recording asyncroniously to the other. When we have read
* the buffer, we wait until the other is filled, and switch
* buffer pointers.
*/
struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
UBYTE *dest = (void *) packet->dp_Arg2;
LONG length, filled;
#ifdef DEBUG
kprintf("ACTION_READ: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
#endif
if(! data->initialized) {
packet->dp_Res2 = InitHData(data);
if(packet->dp_Res2) {
packet->dp_Res1 = -1;
break;
}
}
length = filled = min(data->totallength, packet->dp_Arg3);
if(length <= 0) {
packet->dp_Res1 = length;
data->totallength = -1;
break;
}
if(data->buffer1 == NULL) {
data->buffer1 = AllocVec(data->buffersize, MEMF_PUBLIC);
data->buffer2 = AllocVec(data->buffersize, MEMF_PUBLIC);
data->readreq = AllocVec(sizeof (struct AHIRequest), MEMF_PUBLIC);
if((data->buffer1 == NULL)
|| (data->buffer2 == NULL)
|| (data->readreq == NULL)) {
packet->dp_Res1 = -1;
packet->dp_Res2 = ERROR_NO_FREE_STORE;
break;
}
CopyMem(AHIio, data->readreq, sizeof (struct AHIRequest));
// Fill buffer 2
// Note that io_Offset is always 0 the first time
data->readreq->ahir_Std.io_Command = CMD_READ;
data->readreq->ahir_Std.io_Data = data->buffer2;
data->readreq->ahir_Std.io_Length = data->buffersize;
data->readreq->ahir_Std.io_Offset = 0;
data->readreq->ahir_Type = data->type;
data->readreq->ahir_Frequency = data->freq;
data->readreq->ahir_Volume = data->vol;
data->readreq->ahir_Position = data->pos;
SendIO((struct IORequest *) data->readreq);
// Force buffer switch filling of the other buffer
data->length = data->offset = 0;
// Check if we should write a header first
if(data->format == AIFF) {
if(length < sizeof(struct AIFFHeader)) {
packet->dp_Res1 = -1;
packet->dp_Res2 = ERROR_BAD_NUMBER;
break;
}
FillAIFFheader(data);
CopyMem(&AIFFHeader, dest, sizeof(struct AIFFHeader));
dest += sizeof(struct AIFFHeader);
length -= sizeof(struct AIFFHeader);
}
else if(data->format == AIFC) {
if(length < sizeof(struct AIFCHeader)) {
packet->dp_Res1 = -1;
packet->dp_Res2 = ERROR_BAD_NUMBER;
break;
}
FillAIFCheader(data);
CopyMem(&AIFCHeader, dest, sizeof(struct AIFCHeader));
dest += sizeof(struct AIFCHeader);
length -= sizeof(struct AIFCHeader);
}
}
while(length > 0) {
LONG thislength;
if(data->offset >= data->length) {
void *temp;
temp = data->buffer1;
data->buffer1 = data->buffer2;
data->buffer2 = temp;
if(WaitIO((struct IORequest *) data->readreq)) {
packet->dp_Res1 = -1;
if(data->readreq->ahir_Std.io_Error == AHIE_HALFDUPLEX) {
packet->dp_Res2 = ERROR_OBJECT_IN_USE;
}
else {
packet->dp_Res2 = ERROR_READ_PROTECTED;
}
break;
}
data->length = data->readreq->ahir_Std.io_Actual;
data->offset = 0;
data->readreq->ahir_Std.io_Command = CMD_READ;
data->readreq->ahir_Std.io_Data = data->buffer2;
data->readreq->ahir_Std.io_Length = data->buffersize;
data->readreq->ahir_Type = data->type;
data->readreq->ahir_Frequency = data->freq;
data->readreq->ahir_Volume = data->vol;
data->readreq->ahir_Position = data->pos;
SendIO((struct IORequest *) data->readreq);
} /* if */
thislength = min(data->length - data->offset, length);
CopyMem(data->buffer1 + data->offset, dest, thislength);
dest += thislength;
length -= thislength;
data->offset += thislength;
data->totallength -= thislength;
} /* while */
if(packet->dp_Res2 == 0) {
packet->dp_Res1 = filled;
}
break;
} /* ACTION_READ */
/***********************************************************************/
case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
{
struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
UBYTE *src = (void *) packet->dp_Arg2;
LONG length = packet->dp_Arg3, filled;
#ifdef DEBUG
kprintf("ACTION_WRITE: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
#endif
if(data->buffer1 == NULL) {
// Check headers?
switch(data->args.format) {
case AIFF:
if((((ULONG *) src)[0] != ID_FORM)
|| (((ULONG *) src)[2] != ID_AIFF)) {
packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
}
break;
case AIFC:
if((((ULONG *) src)[0] != ID_FORM)
|| (((ULONG *) src)[2] != ID_AIFC)) {
packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
}
break;
case 0:
if(((ULONG *) src)[0] == ID_FORM) {
if(((ULONG *) src)[2] == ID_AIFF) {
data->args.format = AIFF;
}
else if(((ULONG *) src)[2] == ID_AIFC) {
data->args.format = AIFC;
}
}
break;
default:
break;
}
if(packet->dp_Res2) {
packet->dp_Res1 = -1;
break;
}
if((data->args.format == AIFF) || (data->args.format == AIFC)) {
LONG skiplen = 0;
skiplen = ReadCOMMchunk(data, src, length);
src += skiplen;
length -= skiplen;
}
if(packet->dp_Res2 = InitHData(data)) {
packet->dp_Res1 = -1;
break;
}
data->writing = TRUE;
data->buffer1 = AllocVec(data->buffersize, MEMF_PUBLIC);
data->buffer2 = AllocVec(data->buffersize, MEMF_PUBLIC);
if((data->buffer1 == NULL) || (data->buffer2 == NULL)) {
packet->dp_Res1 = -1;
packet->dp_Res2 = ERROR_NO_FREE_STORE;
break;
}
data->offset = 0;
data->length = (data->buffersize / AHI_SampleFrameSize(data->type))
* AHI_SampleFrameSize(data->type);
}
length = min(data->totallength, length);
filled = min(data->totallength, packet->dp_Arg3);
while(length > 0) {
LONG thislength;
if(data->offset >= data->length) {
packet->dp_Res2 = PlayAndSwap(data, data->length);
if(packet->dp_Res2) {
packet->dp_Res1 = -1;
break;
}
}
thislength = min(data->length - data->offset, length);
CopyMem(src, data->buffer1 + data->offset, thislength);
src += thislength;
length -= thislength;
data->offset += thislength;
data->totallength -= thislength;
} /* while */
if(packet->dp_Res2 == 0) {
packet->dp_Res1 = filled;
}
break;
}
/***********************************************************************/
case ACTION_END: /* FHArg1 Bool:TRUE */
{
struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
#ifdef DEBUG
kprintf("ACTION_END\n");
#endif
// Abort any reading requests
if(data->readreq) {
AbortIO((struct IORequest *) data->readreq);
WaitIO((struct IORequest *) data->readreq);
}
// Finish any playing requests
if(data->writing) {
PlayAndSwap(data, data->offset);
if(data->writereq1) {
WaitIO((struct IORequest *) data->writereq1);
}
if(data->writereq2) {
WaitIO((struct IORequest *) data->writereq2);
}
}
FreeHData(data);
FreeAudio();
break;
}
/***********************************************************************/
case ACTION_IS_FILESYSTEM:
packet->dp_Res1 = DOS_FALSE;
break;
/***********************************************************************/
default:
packet->dp_Res1 = DOS_FALSE;
packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
break;
} /* switch */
if(AllocCnt == 0)
Running = FALSE;
if (packet) {
returnpacket (packet);
#ifdef DEBUG
kprintf("Retured packet\n");
#endif
}
} /* for */
#ifdef DEBUG
kprintf("Dying..!\n");
#endif
UnInitialize();
_exit (0);
}
/******************************************************************************
**** PlayAndSwap **************************************************************
******************************************************************************/
/*
* Starts to play the current buffer. Handles double buffering.
*/
LONG PlayAndSwap(struct HandlerData *data, LONG length) {
void *temp;
temp = data->buffer1;
data->buffer1 = data->buffer2;
data->buffer2 = temp;
temp = data->writereq1;
data->writereq1 = data->writereq2;
data->writereq2 = temp;
if(data->writereq1 == NULL) {
data->writereq1 = AllocVec(sizeof (struct AHIRequest), MEMF_PUBLIC);
if(data->writereq1 == NULL) {
return ERROR_NO_FREE_STORE;
}
CopyMem(AHIio, data->writereq1, sizeof (struct AHIRequest));
}
data->offset = 0;
data->writereq1->ahir_Std.io_Message.mn_Node.ln_Pri = data->priority;
data->writereq1->ahir_Std.io_Command = CMD_WRITE;
data->writereq1->ahir_Std.io_Data = data->buffer2;
data->writereq1->ahir_Std.io_Length = length;
data->writereq1->ahir_Std.io_Offset = 0;
data->writereq1->ahir_Type = data->type;
data->writereq1->ahir_Frequency = data->freq;
data->writereq1->ahir_Volume = data->vol;
data->writereq1->ahir_Position = data->pos;
data->writereq1->ahir_Link = data->writereq2;
SendIO((struct IORequest *) data->writereq1);
if(data->writereq2) {
if(WaitIO((struct IORequest *) data->writereq2)) {
if(data->writereq2->ahir_Std.io_Error == AHIE_HALFDUPLEX) {
return ERROR_OBJECT_IN_USE;
}
else {
return ERROR_WRITE_PROTECTED;
}
}
}
return 0;
}
/******************************************************************************
**** extended2long ************************************************************
******************************************************************************/
/*
* This function translates Apples SANE Extended used in AIFF/AIFC files
* to a LONG. Stolen from Olaf `Olsen' Barthel's AIFF datatype.
*/
long extended2long(extended *ex)
{
unsigned long mantissa;
long exponent,sign;
// We only need 32 bits precision
mantissa = ex->mantissa[0];
// Is the mantissa positive or negative?
exponent = ex->exponent;
if(exponent & 0x8000)
sign = -1;
else
sign = 1;
// Unbias the exponent
exponent = (exponent & 0x7FFF) - 0x3FFF;
// If the exponent is negative, set the mantissa to zero
if(exponent < 0)
mantissa = 0;
else
{
// Special meaning?
exponent -= 31;
// Overflow?
if(exponent > 0)
mantissa = 0x7FFFFFFF;
else
mantissa >>= -exponent; // Let the point float...
}
// That's all...
return(sign * (long)mantissa);
}
/******************************************************************************
**** ulong2extended ***********************************************************
******************************************************************************/
/*
* This function translates an ULONG to Apples SANE Extended
* used in AIFF/AIFC files.
*/
void ulong2extended (ULONG in, extended *ex)
{
ex->exponent=31+16383;
ex->mantissa[1]=0;
while(!(in & 0x80000000))
{
ex->exponent--;
in<<=1;
}
ex->mantissa[0]=in;
}
/******************************************************************************
**** FillAIFFheader ***********************************************************
******************************************************************************/
void FillAIFFheader(struct HandlerData *data) {
AIFFHeader.FORMsize = sizeof(AIFFHeader) + data->totallength - 8;
AIFFHeader.COMMchunk.numChannels = data->channels;
AIFFHeader.COMMchunk.numSampleFrames =
data->totallength / AHI_SampleFrameSize(data->type);
AIFFHeader.COMMchunk.sampleSize = data->bits;
ulong2extended(data->freq, &AIFFHeader.COMMchunk.sampleRate);
AIFFHeader.SSNDsize = sizeof(SampledSoundHeader) + data->totallength;
}
/******************************************************************************
**** FillAIFCheader ***********************************************************
******************************************************************************/
void FillAIFCheader(struct HandlerData *data) {
AIFCHeader.FORMsize = sizeof(AIFCHeader) + data->totallength - 8;
AIFCHeader.COMMchunk.numChannels = data->channels;
AIFCHeader.COMMchunk.numSampleFrames =
data->totallength / AHI_SampleFrameSize(data->type);
AIFCHeader.COMMchunk.sampleSize = data->bits;
ulong2extended(data->freq, &AIFCHeader.COMMchunk.sampleRate);
AIFCHeader.SSNDsize = sizeof(SampledSoundHeader) + data->totallength;
}
/******************************************************************************
**** ReadCOMMchunk ************************************************************
******************************************************************************/
LONG ReadCOMMchunk(struct HandlerData *data, UBYTE *buffer, LONG length) {
UWORD *src = (UWORD *) buffer;
LONG len = (length >> 1) - 2;
ExtCommonChunk *common;
while(len > 0) {
if(((ULONG *) src)[0] == ID_COMM) {
common = (ExtCommonChunk *) (src + 4);
data->channels = common->numChannels;
data->bits = common->sampleSize;
data->totallength = common->numSampleFrames * common->numChannels *
(data->bits <= 8 ? 1 : (data->bits <= 16 ? 2 : (data->bits <= 32 ? 4 : 0)));
data->freq = extended2long(&common->sampleRate);
if(!data->args.channels)
data->args.channels = &data->channels;
if(!data->args.bits)
data->args.bits = &data->bits;
if(!data->args.length)
data->args.length = &data->totallength;
if(!data->args.freq)
data->args.freq = &data->freq;
}
else if(((ULONG *) src)[0] == ID_SSND) {
src += 8;
break;
}
src++;
len--;
}
return (LONG) src - (LONG) buffer;
}
/******************************************************************************
**** AllocAudio ***************************************************************
******************************************************************************/
/*
* If the device isn't already open, open it now
*/
long AllocAudio(int unit) {
long rc = 0;
if(++AllocCnt == 1) {
if(AHImp=CreateMsgPort()) {
if(AHIio=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) {
AHIio->ahir_Version = 4;
AHIDevice=OpenDevice(AHINAME,unit,(struct IORequest *)AHIio,NULL);
}
}
if(AHIDevice) {
rc = ERROR_OBJECT_NOT_FOUND;
}
else {
AHIBase=(struct Library *)AHIio->ahir_Std.io_Device;
}
}
return rc;
}
/******************************************************************************
**** FreeAudio ****************************************************************
******************************************************************************/
/*
* If we're the last user, close the device now
*/
void FreeAudio(void)
{
if(--AllocCnt == 0) {
if(AHIDevice == 0)
CloseDevice((struct IORequest *)AHIio);
AHIDevice = -1;
DeleteIORequest((struct IORequest *)AHIio);
AHIio = NULL;
DeleteMsgPort(AHImp);
AHImp = NULL;
}
}
/******************************************************************************
**** ParseArgs ****************************************************************
******************************************************************************/
/*
* Fill out argument array. Returns 0 on success, else a DOS error code.
*/
long ParseArgs(struct HandlerData *data, char *initstring) {
long rc = 0;
data->rdargs = (struct RDArgs *) AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
if(data->rdargs)
{
data->rdargs->RDA_Source.CS_Buffer = initstring;
data->rdargs->RDA_Source.CS_Length = strlen(initstring);
data->rdargs->RDA_Source.CS_CurChr = 0;
data->rdargs->RDA_Flags |= RDAF_NOPROMPT;
data->rdargs2 = ReadArgs(
"B=BITS/K/N,C=CHANNELS/K/N,F=FREQUENCY/K/N,T=TYPE/K,V=VOLUME/K/N,P=POSITION/K/N,"
"PRI=PRIORITY/K/N,L=LENGTH/K/N,S=SECONDS/K/N,BUF=BUFFER/K/N,UNIT/K/N",
(LONG *) &data->args, data->rdargs);
if(data->rdargs2 != NULL) {
if(! data->args.type) {
data->args.format = 0;
}
else if(Stricmp("SIGNED", data->args.type) == 0) {
data->args.format = SIGNED;
}
else if(Stricmp("AIFF", data->args.type) == 0) {
data->args.format = AIFF;
}
else if(Stricmp("AIFC", data->args.type) == 0) {
data->args.format = AIFC;
}
else {
rc = ERROR_BAD_TEMPLATE;
}
}
else
rc = ERROR_BAD_TEMPLATE;
}
else
rc = ERROR_NO_FREE_STORE;
return rc;
}
/******************************************************************************
**** InitHData ****************************************************************
******************************************************************************/
/*
* Initialize the HandlerData data structure, based on the args structure
* (see ParseArgs()). Returns 0 on success, else a DOS error code.
*/
#define S8bitmode 0
#define S16bitmode 1
#define S32bitmode 8
#define Sstereoflag 2
long InitHData(struct HandlerData *data) {
ULONG bits = 8, channels = 1, freq = 8000;
LONG volume = 100, position = 0, priority = 0,
length = MAXINT, buffersize = 32768;
long rc = 0;
data->initialized = TRUE;
// Fill in default values
if(!data->args.bits)
data->args.bits = &bits;
if(!data->args.channels)
data->args.channels = &channels;
if(!data->args.freq)
data->args.freq = &freq;
if(!data->args.volume)
data->args.volume = &volume;
if(!data->args.position)
data->args.position = &position;
if(!data->args.priority)
data->args.priority = &priority;
if(!data->args.length)
data->args.length = &length;
if(!data->args.buffersize)
data->args.buffersize = &buffersize;
if(!data->args.format)
data->args.format = SIGNED;
// 8, 16 or 32 bit
if(*data->args.bits <= 8)
data->type = S8bitmode;
else if(*data->args.bits <= 16)
data->type = S16bitmode;
else if(*data->args.bits <= 32)
data->type = S32bitmode;
else {
rc = ERROR_OBJECT_WRONG_TYPE;
goto quit;
}
// Mono or stereo
if((*data->args.channels > 2) || (*data->args.channels < 1)) {
rc = ERROR_OBJECT_WRONG_TYPE;
goto quit;
}
if(*data->args.channels == 2)
data->type |= Sstereoflag;
data->bits = *data->args.bits;
data->channels = *data->args.channels;
data->freq = *data->args.freq;
data->vol = *data->args.volume * 0x10000 / 100;
{ // Don't ask why... :(
LONG a;
a = *data->args.position * 0x8000;
a = a / 100 + 0x8000;
data->pos = a;
}
data->priority = *data->args.priority;
if(data->args.seconds) {
data->totallength = *data->args.seconds * data->freq
* AHI_SampleFrameSize(data->type);
}
else {
data->totallength = (*data->args.length / AHI_SampleFrameSize(data->type))
* AHI_SampleFrameSize(data->type);
}
data->format = data->args.format;
switch(data->format) {
case AIFF:
case AIFC:
data->totallength = data->totallength & ~1; // Make even
break;
}
data->buffersize = *data->args.buffersize;
quit:
return rc;
}
/******************************************************************************
**** FreeHData ****************************************************************
******************************************************************************/
/*
* Deallocate the HandlerData structure
*/
void FreeHData(struct HandlerData *data) {
if(data) {
if(data->rdargs2)
FreeArgs(data->rdargs2);
if(data->rdargs);
FreeDosObject(DOS_RDARGS, data->rdargs);
FreeVec(data->buffer1);
FreeVec(data->buffer2);
FreeVec(data->readreq);
FreeVec(data->writereq1);
FreeVec(data->writereq2);
FreeVec(data);
}
}
/******************************************************************************
**** returnpacket *************************************************************
******************************************************************************/
/*
* PACKET ROUTINES. Dos Packets are in a rather strange format as you
* can see by this and how the PACKET structure is extracted in the
* GetMsg() of the main routine.
*/
void returnpacket (struct DosPacket *packet) {
struct Message *mess;
struct MsgPort *replyPort;
replyPort = packet->dp_Port;
mess = packet->dp_Link;
packet->dp_Port = PktPort;
mess->mn_Node.ln_Name = (char *) packet;
PutMsg (replyPort, mess);
}
/******************************************************************************
**** Initialize ***************************************************************
******************************************************************************/
/*
* During initialization DOS sends us a packet and sets our dn_SegList
* pointer. If we set our dn_Task pointer than every Open's go to the
* same handler (this one). If we set dn_Task to NULL, every Open()
* will create a NEW instance of this process via the seglist, meaning
* our process must be reentrant (i.e. -r option).
*
* note: dn_Task points to the MESSAGE PORT portion of the process
* (or your own custom message port).
*
* If we clear the SegList then we also force DOS to reload our process
* from disk, but we also need some way of then UnLoadSeg()ing it ourselves,
* which we CANNOT do from this process since it rips our code out from
* under us.
*/
void Initialize () {
struct DeviceNode *dn;
struct Process *proc = (struct Process *) FindTask (NULL);
struct DosPacket *packet;
/*
* Handle initial message.
*/
struct Message *msg;
WaitPort (PktPort);
msg = GetMsg (PktPort);
packet = (struct DosPacket *) msg->mn_Node.ln_Name;
DevNode = dn = BTOC (packet->dp_Arg3);
dn->dn_Task = NULL;
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
returnpacket (packet);
}
/******************************************************************************
**** UnInitialize *************************************************************
******************************************************************************/
void UnInitialize (void) {
struct DeviceNode *dn = DevNode;
dn->dn_Task = NULL;
}